Merged
Conversation
Fix/add missing func
🚨 Report Summary
For more details view the full report in OpenZeppelin Code Inspector |
There was a problem hiding this comment.
Pull request overview
This PR updates the Rewards system to support a unified treasury for ERC20/ERC721/ERC1155 (including reservation tracking) and adds tooling/tests around the new treasury balance reporting, while also updating deployment configuration/constants for new contracts on Arbitrum.
Changes:
- Converted
Rewardsto a UUPS-upgradeable contract and added NFT (ERC721/ERC1155) treasury reservation + balance reporting viagetAllTreasuryBalances. - Expanded test coverage for soulbound + NFT treasury flows (reserve/withdraw/claim) and added multiple Hardhat scripts for deployment/setup/verification.
- Updated Arbitrum deployment/upgrade configuration and constructor-arg constants to include
GReceiptsand new token/address parameters.
Reviewed changes
Copilot reviewed 18 out of 18 changed files in this pull request and generated 17 comments.
Show a summary per file
| File | Description |
|---|---|
| test/rewardsSoulbound.test.ts | Updates Rewards deployment to UUPS proxy and adds tests for getAllTreasuryBalances + ERC1155 reservation tracking. |
| test/rewardsNftTreasury.test.ts | New suite validating ERC721/ERC1155 treasury reservation, protection on withdraw, and claim distribution flows. |
| scripts/verifyRewards.ts | Adds a verification script to inspect on-chain Rewards state including getAllTreasuryBalances. |
| scripts/setupWalletForRewards.ts | Adds helper script to whitelist/mint assets to a target wallet for rewards setup. |
| scripts/setupUSDCReward.ts | Adds helper script to deposit USDC and create a USDC reward. |
| scripts/setupAllRewards.ts | Adds an end-to-end setup script for multiple badge rewards + USDC reward creation. |
| scripts/depositExtraUSDC.ts | Adds helper script to top up USDC treasury and inspect available/reserved balances. |
| scripts/deployRewardsWithRoles.ts | Adds deployment script intended to deploy AccessToken/Rewards and grant roles. |
| scripts/deployRewardsUUPS.ts | Adds UUPS deployment script for Rewards and initial token whitelisting. |
| scripts/deployAllBadges.ts | Adds script to deploy multiple badge contracts + MockUSDC and perform basic setup. |
| scripts/createInitialRewards.ts | Adds script to fund treasury (ERC20/1155) and prepare initial rewards creation. |
| scripts/checkApprovals.ts | Adds script to inspect badge approvals/balances for a wallet. |
| hardhat.config.ts | Enables unlimited contract size on local hardhat network for development. |
| contracts/upgradeables/soulbounds/Rewards.sol | Core changes: UUPS upgradeability, unified token whitelist with types, NFT reservation accounting, and getAllTreasuryBalances. |
| contracts/upgradeables/ercs/ERCWhitelistSignatureUpgradeable.sol | Tracks whitelist signer list for enumeration and updates storage gap. |
| constants/upgrades/index.ts | Adds upgrade configuration entry for GReceipts on Arbitrum One. |
| constants/deployments/deployments-arbitrum-one.ts | Adds GReceipts deployment config on Arbitrum One. |
| constants/constructor-args.ts | Updates addresses/args for Arbitrum networks and adds GReceiptsArgs.ARBITRUM_ONE. |
Comments suppressed due to low confidence (7)
contracts/upgradeables/soulbounds/Rewards.sol:66
- Rewards is now UUPS/Initializable but the contract lacks an implementation constructor that disables initializers. Without
constructor() { _disableInitializers(); }, someone can initialize the implementation contract directly and grant themselves roles, which is a common UUPS footgun. Also consider importingUUPSUpgradeablefrom@openzeppelin/contracts-upgradeable/...for consistency with the other upgradeable base contracts.
contracts/upgradeables/soulbounds/Rewards.sol:403 _countUniqueErc1155TokenIds()allocatesitemIds.length * 10slots for tracking unique (address,tokenId) pairs. Since there is no hard cap of 10 ERC1155 rewards per item,count++can exceed the allocated length and revert at runtime. Consider a two-pass approach: first count the total number of ERC1155 reward entries across allitemIdsto size the arrays, or maintain explicit tracking of seen pairs in storage when rewards are created.
contracts/upgradeables/soulbounds/Rewards.sol:240getAllTreasuryBalances()can return multiple entries for the same ERC1155 contract address (different token IDs), but the return values don’t include the ERC1155tokenIdfor each row. That makes the result ambiguous for consumers (duplicate addresses with different balances/reserved) and hard to act on (e.g., withdraw a specific id). Consider returning a paralleluint256[] tokenIds(0 for ERC20/ERC721) or a struct/tuple that includes(tokenAddress, tokenId, type, balances, metadata)per entry.
contracts/upgradeables/soulbounds/Rewards.sol:271getAllTreasuryBalances()can revert with an out-of-bounds write:totalCountis computed aserc20AndErc721Count + _countUniqueErc1155TokenIds(), but the loop always writesaddresses[currentIndex] = tokenAddresseven for ERC1155 entries. If only ERC1155 tokens are whitelisted and there are no rewards yet (sototalCount == 0), this write reverts. Move the assignment inside the ERC20/ERC721 branches (or guard withif (currentIndex < totalCount)), and ensure ERC1155-only whitelists return empty arrays rather than reverting.
contracts/upgradeables/soulbounds/Rewards.sol:128- Introducing
tokenTypeschanges runtime assumptions for already-deployed proxies: existingwhitelistedTokenListentries (from before this mapping existed) will havetokenTypes[token] == 0(ETHER), which can causegetAllTreasuryBalances()to miscount/allocate arrays and potentially revert. If this contract is being upgraded in-place, add a migration path (e.g., manager-only function to backfilltokenTypesfor existing whitelisted tokens) or makegetAllTreasuryBalancesresilient to unset types.
contracts/upgradeables/soulbounds/Rewards.sol:666 whitelistTokennow allows whitelisting ERC721/ERC1155, butdepositToTreasury,getTreasuryBalance, and related treasury helpers still assume the token is ERC20 (they callSafeERC20/IERC20.balanceOf). This makes it easy to whitelist an NFT and then hit confusing reverts when using treasury ERC20 flows. Consider enforcing_type == LibItems.RewardType.ERC20insidedepositToTreasury(and other ERC20-only helpers) or splitting the API so NFT treasury operations cannot be mixed with ERC20 deposit calls.
contracts/upgradeables/soulbounds/Rewards.sol:720removeTokenFromWhitelistenforcesbalance == 0for ERC20 and ERC721, but for ERC1155 it only checkserc1155TotalReservedand does not prevent removing a token while the contract still holds ERC1155 balances. That can make assets harder to discover/operate on (e.g.,getAllTreasuryBalancesonly walks whitelisted tokens) and blocks the ERC1155-specific withdraw helper which requireswhitelistedTokens[_token]. If you can’t enumerate all ERC1155 IDs, consider tracking received ERC1155 IDs in storage (via ERC1155Receiver hooks) and preventing removal while any tracked balance > 0, or document/handle the removal semantics explicitly.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
karacurt
approved these changes
Feb 4, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Issue: Missing func with new treasuries for nfts
🐵 Description
This pull request introduces several important changes to the deployment configuration, contract logic, and developer tooling for the project. The updates improve deployment flexibility for new contracts, enhance whitelist management in the upgradeable ERC contract, and add useful scripts for testing and setup. Below are the most significant changes grouped by theme:
Deployment Configuration and Contract Arguments
GReceiptscontract on Arbitrum One, including its constructor arguments and upgrade settings in bothdeployments-arbitrum-one.tsandupgrades/index.ts. This enables automated deployment and upgrade management forGReceiptsalongsideGUnits. [1] [2] [3] [4]GUNITS_ARBITRUM_SEPOLIA,GUNITS_ARBITRUM_ONE, andUSDXM_ARBITRUM_SEPOLIA. AdjustedGUnitsArgsto use the correct payment tokens for each network. [1] [2]Upgradeable Contract Logic
ERCWhitelistSignatureUpgradeablecontract to maintain an explicit list of whitelist signers, enabling enumeration and improved management. Added logic to update this list when signers are added or removed, and exposed an internal getter for the list. [1] [2] [3]Developer Tooling and Scripts
deployAllBadges.tsto automate deployment of multiple ERC1155Soulbound badge contracts and a mock USDC contract, including setup for initial tokens and whitelisting. This script also outputs environment variables and verification commands for further setup.createInitialRewards.tsto facilitate creation and funding of initial rewards in the Rewards contract, including logic for ERC20 and ERC1155 deposits and (commented) reward token creation.checkApprovals.tsto check approval status and balances for a target wallet across multiple badge contracts, aiding in troubleshooting and setup.hardhatnetwork, improving local development flexibility.